"""
@Author: li
@Email: lijianqiao2906@live.com
@FileName: deps.py
@DateTime: 2025/07/05
@Docs: FastAPI依赖注入
"""

from typing import Annotated, cast

from fastapi import Depends, HTTPException, Query, Request, status
from fastapi.security import OAuth2PasswordBearer
from redis.asyncio import Redis

from app.core.config import settings
from app.core.exceptions import UnauthorizedException
from app.models import User
from app.services.user import user_service
from app.utils.security import decode_access_token

# OAuth2 认证方案，它会从请求的 Authorization 头中查找 Bearer Token
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/login")


async def get_redis() -> Redis:
    """获取Redis连接"""
    from app.main import app

    if not hasattr(app.state, "redis") or app.state.redis is None:
        raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Redis连接不可用")
    return app.state.redis


async def get_pagination_params(
    page: Annotated[int, Query(ge=1)] = 1,
    page_size: Annotated[int, Query(ge=1, le=100)] = 10,
) -> dict[str, int]:
    """获取分页参数"""
    return {"page": page, "page_size": page_size}


async def verify_api_access(request: Request) -> None:
    """验证API访问权限"""
    # 检查是否启用了监控功能
    if request.url.path == settings.METRICS_PATH and not settings.ENABLE_METRICS:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="监控功能未启用")

    # 在生产环境中可以添加更多安全检查
    # 例如：API密钥验证、IP白名单等
    if settings.IS_PRODUCTION:
        # 示例：检查特定路径的访问权限
        protected_paths = [settings.METRICS_PATH, "/api/admin"]
        if any(request.url.path.startswith(path) for path in protected_paths):
            # 这里可以添加认证逻辑
            api_key = request.headers.get("X-API-Key")
            if not api_key:
                raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="需要API密钥")


async def get_client_info(request: Request) -> dict[str, str]:
    """获取客户端信息"""
    return {
        "ip": request.client.host if request.client else "unknown",
        "user_agent": request.headers.get("user-agent", ""),
        "host": request.headers.get("host", ""),
        "request_id": request.headers.get("X-Request-ID", ""),
    }


async def get_current_user(token: str = Depends(oauth2_scheme)) -> User:
    """
    解码JWT并获取当前用户
    - 从请求头中提取Token
    - 解码并验证Token
    - 根据Token中的用户ID从数据库获取用户
    - 如果验证失败则抛出HTTPException
    """
    payload = decode_access_token(token)
    if not payload:
        raise UnauthorizedException(detail="无效的认证令牌")

    user_id = payload.get("sub")
    if user_id is None:
        raise UnauthorizedException(detail="无效的认证令牌")

    # 使用服务层方法获取用户并预加载角色
    user_model = await user_service.get_user_with_roles(int(user_id))
    if not user_model:
        raise UnauthorizedException(detail="用户不存在")
    user = cast(User, user_model)

    if user.is_deleted:
        raise UnauthorizedException(detail="用户不存在或已被删除")

    if not user.is_active:
        raise UnauthorizedException(detail="用户已被禁用")

    return user


async def get_current_superuser(current_user: User = Depends(get_current_user)) -> User:
    """获取当前超级用户"""
    if not current_user.is_superuser:
        raise UnauthorizedException(detail="需要超级用户权限")
    return current_user


class PermissionChecker:
    """
    权限检查器依赖类。
    使用方法:
    - 在路由依赖中: Depends(PermissionChecker("system:user:list", "system:user:view"))
    """

    def __init__(self, *permissions: str):
        self.required_permissions = set(permissions)

    async def __call__(self, current_user: User = Depends(get_current_user)):
        """
        检查当前用户是否拥有所有必需的权限。
        """
        # 超级用户拥有所有权限
        if current_user.is_superuser:
            return

        # 获取用户的所有权限编码
        user_permissions = await user_service.get_user_permissions(current_user.id)

        # 检查所需权限是否都存在于用户权限中
        if not self.required_permissions.issubset(user_permissions):
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail=f"权限不足，需要以下权限: {', '.join(self.required_permissions)}",
            )


# 常用依赖
RedisDep = Annotated[Redis, Depends(get_redis)]
PaginationDep = Annotated[dict[str, int], Depends(get_pagination_params)]
ClientInfoDep = Annotated[dict[str, str], Depends(get_client_info)]
ApiAccessDep = Annotated[None, Depends(verify_api_access)]
CurrentUserDep = Annotated[User, Depends(get_current_user)]
SuperUserDep = Annotated[User, Depends(get_current_superuser)]
